#!/usr/bin/env python
# -*- coding: utf-8 -*-
#

import  socket
import  asyncore

PORT_DEFAULT = 4344

class   ReactorContext(object) :
    '''
    context(proxy) object for reactor
    '''
    def __init__(self, reactor, id, addr) :
        self.id = id
        self.address = addr
        self.__reactor = reactor
        
    def response(self, data)
        self.__reactor.response(data, self)
        
    # class ReactorContext
    

class   UDPReactor(asyncore.dispatcher)  :
    '''
    Reactor for UDP socket
    '''
    MAX_PACKET_SIZE = 65536 - 4096
    
    def __init__(self, port=PORT_DEFAULT) :
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.set_reuse_addr()
        self.bind( ('', port) )
        #self.settimeout(1.0)
        self.__queue_in  = []
        self.__queue_out = []
        
        self.__requestHandler = None
        # __init__()
        
    def addRequestHandler(self, handler) :
        self.__requestHandler = handler
        
    def response(self, data, context) :
        # append response to queue-out
        self.__queue_out.append( (data, context.address) )
        
        
    def readable(self) :
        return  True
        
    def handle_read(self) :
        try :
            data, peer_addr = self.socket.recv_from(self.MAX_PACKET_SIZE)
            # handle request by callback
        except socket.timeout :
            pass
        except socket.error, why :
            self.handle_error()
            return
            
        if self.__requestHandler is None :
            raise RuntimeError, 'No REQUEST handler is set.'
        id = 0
        context = ReactorContext(self, id, peer_addr)
        self.__requestHandler(data, context)
        
        # handle_read()
        
    def writable(self) :
        return  len(self.__queue_out) > 0
        
    def handle_write(self) :
        self.__queue_out = []
        pass
        
    def handle_connect(self) :
        pass
        
    def handle_close(self) :
        self.close()
        
    # class UDPReactor
    
class   Node(object) :
    '''
    Kademlia Node Class
    '''
    
    def __init__(self, address) :
        '''
        \param address -- address of node,  format as a (ip, port) tuple
        '''
        self.__address = address
        
    def join(self, seed_node) :
        '''
        join kad net
        
        \param seed_node -- address of seed_node
        '''
        return  NotImplementedError
        
    def ping(self, node) :
        '''
        ping kad node, to probe if the node exists
        
        \param node -- address of node
        '''
        return  NotImplementedError
        
    def find(self, node) :
        '''
        find kad node
        
        \param node -- address of node
        '''
        return  NotImplementedError
        
    def put(self, key, value) :
        '''
        '''
        return  NotImplementedError
        
    def get(self, key) :
        '''
        '''
        return  NotImplementedError
        